﻿using SiMay.Sockets.Tcp;
using SiMay.Sockets.Tcp.Server;
using SiMay.Sockets.Tcp.Session;
using SiMay.Sockets.Tcp.TcpConfiguration;
using SyncFileCommon.Class;
using SyncFileCommon.Model;
using System.Net;

namespace SyncFileCommon.BLL
{


    public delegate void ServerEventHandler(TcpSocketCompletionNotify e, TcpSocketSaeaSession session);

    public class ServerBLL
    {

        public event ServerEventHandler ServerEvent;

        /// <summary>
        /// 设置下载文件保存路径事件
        /// </summary>
        public Func<string, long, string> FileDownloadBeginEvent;

        /// <summary>
        /// 触发消息事件
        /// </summary>
        public Action<string, string> MessageEvent;

        /// <summary>
        /// TCPServerSocket服务
        /// </summary>
        private TcpSocketSaeaServer TcpServer = null;


        /// <summary>
        /// 是否已经监听
        /// </summary>
        private bool IsListen = false;

        /// <summary>
        /// 服务器监听的端口号
        /// </summary>
        private int ServerPort = 0;

        /// <summary>
        /// 开始运行服务
        /// </summary>
        public void ServerStart()
        {
            //加载配置
            SyncFileCommon.BLL.ConfigBLL.LoadConfig();

            ServerPort = ConfigBLL.ServiceConfig.ServicePort;

            //模式说明
            //Full模式:仅接收发送数据（高性能的数据接收模型，可启用TcpKeepAlive选项）注：数据压缩丶AppKeepAlive选项在Full模式下启用无效
            //Pack模式:自动处理分包（高性能的数据接收模型，自动处理分包，可启用数据压缩丶应用层心跳包丶TcpKeepAlive选项）

            TcpSocketSaeaServerConfiguration serverConfig = new TcpSocketSaeaServerConfiguration();
            serverConfig.CompressTransferFromPacket = false;


            TcpServer = TcpSocketsFactory.CreateServerAgent(TcpSocketSaeaSessionType.Packet, serverConfig, Server_CompletetionNotify);

            TcpServer.Listen(new IPEndPoint(IPAddress.Parse("0.0.0.0"), ServerPort));

            IsListen = true;

        }

        /// <summary>
        /// 重新加载配置
        /// </summary>
        public void ServerReLoadConfig()
        {
            //加载配置
            SyncFileCommon.BLL.ConfigBLL.LoadConfig();

            if (ServerPort != ConfigBLL.ServiceConfig.ServicePort)
            {
                ServerStop();
                ServerStart();
            }
            UserBLL.UserListGet();
            SyncDirectoryBLL.DirectoryListGet();

        }

        /// <summary>
        /// 触发的事件
        /// </summary>
        /// <param name="e"></param>
        /// <param name="session"></param>
        private void Server_CompletetionNotify(TcpSocketCompletionNotify e, TcpSocketSaeaSession session)
        {
            switch (e)
            {
                case TcpSocketCompletionNotify.OnConnected:
                    //session初始化完成连接的事件
                    //调用session.SendAsync();对session发送消息
                    //调用session.Close(true)断开session连接，并通知断开事件
                    //可在session.AppTokens中绑定应用对象，以便在其他异步事件中调用
                    this.ServerEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnSend:
                    //session发送数据通知事件
                    //session.SendTransferredBytes == 以发送数据长度
                    this.ServerEvent?.Invoke(e, session);
                    break;
                case TcpSocketCompletionNotify.OnDataReceiveing:
                    //session数据接收通知事件
                    //session.ReceiveBytesTransferred == 本次接收数据长度 
                    this.ServerEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnDataReceived:
                    //Packet模式session自动处理分包的完成事件
                    byte[] pack = session.CompletedBuffer;//完整数据包
                    var _rd = SessionHelper.RecieverData(session, pack, FileDownloadBegin);
                    if (new SessionHelper.DataPackType[] { SessionHelper.DataPackType.DataOnePack, SessionHelper.DataPackType.DataMultiplePack, SessionHelper.DataPackType.FileDataPack }.Contains(_rd.PackType))
                    {
                        if (_rd.DataAllLength == _rd.RedeiverLength)
                        {
                            if (SessionHelper.DataPackType.FileDataPack == _rd.PackType)
                            {
                                MessageEvent?.Invoke("下载文件完成", "文件路径:" + System.Text.Encoding.UTF8.GetString(_rd.Data));
                            }
                            else
                            {
                                switch (MessageHelper.GetMessageHead<MessageHead>(_rd.Data))
                                {
                                    case MessageHead.JsonString:
                                        {
                                            string _s = MessageHelper.GetMessageStringData(_rd.Data);
                                            JsonHelper _json = new JsonHelper(_s);
                                            string _messageType = _json.GetVar("MessageType");
                                            switch (_messageType)
                                            {
                                                case "UserLogin":
                                                    {
                                                        string _userName = _json.GetVar("UserName");
                                                        string _password = _json.GetVar("Password");
                                                        //判断用户名和密码是否正确
                                                        if (UserBLL.UserList == null)
                                                        {
                                                            UserBLL.UserListGet();
                                                        }
                                                        UserModel _user = UserBLL.UserList.Find(it => it.UserName == _userName && it.Password == _password);
                                                        if (_user == null)
                                                        {
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper().AddVar("MessageType", "LoginFail").JsonStr));
                                                            MessageEvent?.Invoke("用户登录失败", "IP:[" + (session.Socket.RemoteEndPoint as IPEndPoint).Address.ToString() + "],用户名:" + _userName);
                                                        }
                                                        else
                                                        {
                                                            if (session.AppTokens == null)
                                                            {
                                                                session.AppTokens = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
                                                            }
                                                            session.AppTokens.AddOrUpdate("UserName", _userName, (key, oldValue) => { return _userName; });
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper().AddVar("MessageType", "LoginOK").JsonStr));
                                                            MessageEvent?.Invoke("用户登录成功", "IP:[" + (session.Socket.RemoteEndPoint as IPEndPoint).Address.ToString() + "],用户名:" + _userName);
                                                        }

                                                        break;
                                                    }
                                                case "GetDirSubDirectory":
                                                    {
                                                        //根据文件夹路径获取文件夹下的子文件夹名
                                                        string _userName = string.Empty;
                                                        if (session.AppTokens != null)
                                                        {
                                                            //从AppTokens中获取登录的用户名
                                                            _userName = Convert.ToString(session.AppTokens.GetValueOrDefault("UserName", string.Empty));
                                                        }
                                                        //如果没有登录返回客户端先登录
                                                        if (string.IsNullOrWhiteSpace(_userName))
                                                        {
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "MessageError")
                                                               .AddVar("Message", "请登录后操作").JsonStr));
                                                            return;
                                                        }
                                                        //获取文件夹路径
                                                        string _dirPath = _json.GetVar("DirPath");
                                                        //加载共享的文件夹列表信息
                                                        if (SyncDirectoryBLL.DirectoryList == null)
                                                        {
                                                            SyncDirectoryBLL.DirectoryListGet();
                                                        }

                                                        //获取登录用户可操作的文件夹信息
                                                        List<SyncDirectoryModel> _DirectoryList = SyncDirectoryBLL.DirectoryList.FindAll(it => it.UserList.Split("|", StringSplitOptions.RemoveEmptyEntries).Contains(_userName) || it.UserList == "[All]");
                                                        if (string.IsNullOrWhiteSpace(_dirPath))
                                                        {
                                                            //如果是空路径则返回所有可操作的文件夹跟路径
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "SubDirectoryInfo")
                                                               .AddVar("Data", JsonHelper.GetJsonStrFromObject(_DirectoryList.Select(it => it.DirectoryPath))).JsonStr));
                                                        }
                                                        else
                                                        {
                                                            //判断请求的路径是否包含可操作的文件夹路径
                                                            if (_DirectoryList.Find(it => _dirPath.Contains(it.DirectoryPath)) != null)
                                                            {
                                                                List<string> _subDirectoryList = FileHelper.GetDirectorySubDirectory(_dirPath);
                                                                if (_subDirectoryList == null)
                                                                {
                                                                    _subDirectoryList = new List<string>();
                                                                }

                                                                MessageEvent?.Invoke("获取文件夹子目录信息", _dirPath);
                                                                SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                                    .AddVar("MessageType", "SubDirectoryInfo")
                                                                    .AddVar("DirPath", _dirPath)
                                                                    .AddVar("Data", JsonHelper.GetJsonStrFromObject(_subDirectoryList)).JsonStr));

                                                            }
                                                            else
                                                            {
                                                                SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                                    .AddVar("MessageType", "MessageError")
                                                                    .AddVar("Message", "没有文件夹信息获取权限").JsonStr));
                                                                return;
                                                            }
                                                        }

                                                        break;
                                                    }
                                                case "GetDirFileInfo":
                                                    {
                                                        //获取共享文件夹文件信息
                                                        string _userName = string.Empty;
                                                        if (session.AppTokens != null)
                                                        {
                                                            //从AppTokens中获取登录的用户名
                                                            _userName = Convert.ToString(session.AppTokens.GetValueOrDefault("UserName", string.Empty));
                                                        }
                                                        //如果没有登录返回客户端先登录
                                                        if (string.IsNullOrWhiteSpace(_userName))
                                                        {
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "MessageError")
                                                               .AddVar("Message", "请登录后操作").JsonStr));
                                                            return;
                                                        }
                                                        //获取文件夹路径
                                                        string _dirPath = _json.GetVar("DirPath");
                                                        //加载共享的文件夹列表信息
                                                        if (SyncDirectoryBLL.DirectoryList == null)
                                                        {
                                                            SyncDirectoryBLL.DirectoryListGet();
                                                        }

                                                        //获取登录用户可操作的文件夹信息
                                                        List<SyncDirectoryModel> _DirectoryList = SyncDirectoryBLL.DirectoryList.FindAll(it => it.UserList.Split("|", StringSplitOptions.RemoveEmptyEntries).Contains(_userName) || it.UserList == "[All]");
                                                        if (string.IsNullOrWhiteSpace(_dirPath))
                                                        {
                                                            //如果是空路径则返回错误
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "MessageError")
                                                               .AddVar("Message", "同步文件夹路径不可为空").JsonStr));
                                                        }
                                                        else
                                                        {
                                                            //判断请求的路径是否包含可操作的文件夹路径
                                                            if (_DirectoryList.Find(it => _dirPath.Contains(it.DirectoryPath)) != null)
                                                            {
                                                                List<FileData> _fileList = FileHelper.GetDirectoryFile(_dirPath);
                                                                if (_fileList == null)
                                                                {
                                                                    _fileList = new List<FileData>();
                                                                }

                                                                MessageEvent?.Invoke("获取文件夹文件信息", _dirPath);
                                                                SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                                    .AddVar("MessageType", "DirFileInfo")
                                                                    .AddVar("DirPath", _dirPath)
                                                                    .AddVar("Data", JsonHelper.GetJsonStrFromObject(_fileList)).JsonStr));

                                                            }
                                                            else
                                                            {
                                                                SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                                    .AddVar("MessageType", "MessageError")
                                                                    .AddVar("Message", "没有文件夹信息获取权限").JsonStr));
                                                                return;
                                                            }
                                                        }

                                                        break;

                                                    }
                                                case "DownFile":
                                                    {
                                                        //请求下载文件

                                                        string _userName = string.Empty;
                                                        if (session.AppTokens != null)
                                                        {
                                                            //从AppTokens中获取登录的用户名
                                                            _userName = Convert.ToString(session.AppTokens.GetValueOrDefault("UserName", string.Empty));
                                                        }
                                                        //如果没有登录返回客户端先登录
                                                        if (string.IsNullOrWhiteSpace(_userName))
                                                        {
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "MessageError")
                                                               .AddVar("Message", "请登录后操作").JsonStr));
                                                            return;
                                                        }
                                                        //获取文件夹路径
                                                        string _filePath = _json.GetVar("FilePath");

                                                        if (string.IsNullOrWhiteSpace(_filePath))
                                                        {
                                                            //如果是空路径则返回错误
                                                            SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                               .AddVar("MessageType", "MessageError")
                                                               .AddVar("Message", "同步文件路径不可为空").JsonStr));
                                                            return;
                                                        }

                                                        //加载共享的文件夹列表信息
                                                        if (SyncDirectoryBLL.DirectoryList == null)
                                                        {
                                                            SyncDirectoryBLL.DirectoryListGet();
                                                        }

                                                        //获取登录用户可操作的文件夹信息
                                                        List<SyncDirectoryModel> _DirectoryList = SyncDirectoryBLL.DirectoryList.FindAll(it => it.UserList.Split("|", StringSplitOptions.RemoveEmptyEntries).Contains(_userName) || it.UserList == "[All]");

                                                        {
                                                            //判断请求的路径是否包含可操作的文件夹路径
                                                            if (_DirectoryList.Find(it => _filePath.Contains(it.DirectoryPath)) != null)
                                                            {
                                                                MessageEvent?.Invoke("下载文件", _filePath);
                                                                SessionHelper.SendFile(session, _filePath);
                                                            }
                                                            else
                                                            {
                                                                SessionHelper.SendData(session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, new JsonHelper()
                                                                    .AddVar("MessageType", "MessageError")
                                                                    .AddVar("Message", "没有文件下载权限").JsonStr));
                                                                return;
                                                            }
                                                        }

                                                        break;
                                                    }
                                            }

                                            break;
                                        }

                                }
                            }
                        }
                        else
                        {
                            //MessageEvent?.Invoke("接收消息中", "接收消息中:[" + _rd.RedeiverLength.ToString() + "/" + _rd.DataAllLength.ToString() + "]");
                        }
                    }
                    this.ServerEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnClosed:
                    //session断开通知事件
                    this.ServerEvent?.Invoke(e, session);
                    break;
            }


        }

        /// <summary>
        /// 服务运行状态  0,未监听  1，已监听
        /// </summary>
        /// <returns></returns>
        public int ServerStateGet()
        {
            if (TcpServer == null)
            {
                return 0;
            }

            if (IsListen)
            {
                return 1;
            }

            return 0;
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void ServerStop()
        {
            TcpServer.DisconnectAll(true);
            IsListen = false;
            TcpServer = null;
        }

        /// <summary>
        /// 文件下载前设置文件保存路径
        /// </summary>
        /// <param name="serverFilePath">服务器上文件路径</param>
        /// <param name="fileSize">文件大小(字节数)</param>
        /// <returns></returns>
        private string FileDownloadBegin(string serverFilePath, long fileSize)
        {
            return FileDownloadBeginEvent?.Invoke(serverFilePath, fileSize);
        }
    }
}
